'use strict';
const PWD_VALIDATION = {type: 'password', min: 6, max: 16}
const loginRule = {
  username: {
    type: 'username',
    required: true
  },
  password: PWD_VALIDATION
}

module.exports = app => {
  class AuthController extends app.Controller {
    async logined (ctx) {
      let username = ctx.session.username
      let logined = await ctx.helper.auth.logined({ctx, username})
      ctx.helper.rest.resp({
        ctx,
        code: logined ? 0 : 'unlogined',
        message: logined ? 'authed.' : 'unlogined.'
      })
    }

    async login (ctx) {
      let [error] = ctx.app.validator.validate(loginRule, ctx.request.body) || []

      if (error) {
        ctx.helper.rest.resp({ctx, error: ctx.errors.INVALID_PARAMS })
        return
      }

      let { username, password } = ctx.request.body

      let foundUser = new ctx.app.model.user.doc({username, password})
      let query = {
        username: foundUser.username,
        password: foundUser.hash_password
      }
      let results = await ctx.app.model.user.doc.find(query).limit(1)

      if (!results || !results.length) {
        ctx.helper.rest.resp({ ctx, error: ctx.errors.WRONG_PWD })
        return
      }

      let [user] = results
      let data = user.toObject({
        virtuals: true,
        transform: function (doc, ret, options) {
          delete ret._id
          delete ret.password
          delete ret.hash_password
          return ret
        }
      })

      ctx.session.username = user.username

      ctx.helper.rest.resp({ ctx, message: 'auth success.' })
    }

    async logout (ctx) {
      ctx.helper.auth.logout({ctx})

      ctx.helper.rest.resp({ctx, message: 'logout success.'})
    }

    // TODO: page token required.
    async userExists (ctx) {
      let username = ctx.request.get('x-username')
      let [error] = ctx.app.validator.validate({
        username: ctx.validation.username
      }, {username}) || []

      if (error) {
        ctx.helper.rest.resp({ctx, error: ctx.errors.INVALID_PARAMS, message: 'invalid username.' })
        return
      }

      if (!username) {
        if (ctx.helper.abortOnError({ctx, error: ctx.errors.INVALID_PARAMS })) return
      }

      let user = await ctx.app.model.user.doc.findOne({username}).catch(ctx.helper.genAppError({ctx}))

      if (!user) {
        ctx.helper.rest.resp({ctx, error: ctx.errors.NOT_FOUND, message: `user doesn't exist.`})
        return
      }

      ctx.helper.rest.resp({ctx, message: `username '${username}' is valid.`})
    }

    async updatePwd (ctx) {
      let username = ctx.session.username
      let logined = await ctx.helper.auth.logined({ctx, username})

      if (!logined) {
        if (ctx.helper.abortOnError({ctx, error: ctx.errors.UNLOGINED })) return
      }

      let { old_password, new_password, confirm_password } = ctx.request.body || {}

      if (old_password == new_password) {
        ctx.helper.rest.resp({ctx, error: ctx.errors.INVALID_PARAMS, message: 'same new password and old password.'})
        return
      }

      if (new_password !== confirm_password) {
        ctx.helper.rest.resp({ctx, error: ctx.errors.NOT_SAME, message: 'new password is not same with confirm password.'})
        return
      }

      let [error] = ctx.app.validator.validate({
        old_password: PWD_VALIDATION,
        new_password: PWD_VALIDATION,
        confirm_password: PWD_VALIDATION
      }, { old_password, new_password, confirm_password }) || []

      if (error) {
        ctx.helper.rest.resp({ctx, code: 1, error })
        return
      }

      let queryUser = new ctx.app.model.user.doc({username, password: old_password})
      let query = {
        username: queryUser.username,
        password: queryUser.hash_password
      }

      let results = await ctx.app.model.user.doc.find(query).limit(1)

      if (!results || !results.length) {
        ctx.helper.rest.resp({ ctx, error: ctx.errors.WRONG_PWD })
        return
      }

      queryUser.password = new_password
      let updateRes = await ctx.app.model.user.doc.findOneAndUpdate(query, {
        password: queryUser.hash_password
      }).catch(ctx.helper.genAppError({ctx}))

      // TODO: check it
      if (ctx.helper.abortOnError({ctx, error: updateRes})) return

      // unset session
      ctx.helper.auth.logout({ctx})

      ctx.helper.rest.resp({ctx, message: 'password change success, re-login is required.'})
    }
  }

  return AuthController;
};
